; 实验16 编写包含多个子程序的中断例程
; 安装一个int 7ch中断例程，为显示提供如下功能：
; 1.清屏
; 2.设置前景色
; 3.设置背景色
; 4.向上滚动一行
; 入口参数：ah传递功能号：0-清屏，1-设置前景色，2-设置背景色，3-向上滚动一行
; al传递颜色值，al in {0,1,2,3,4,5,6,7}
assume cs:codesg,ss:stacksg

stacksg segment
    db 128 dup(0)
stacksg ends

codesg segment
    table dw cls,setfb,setbg,scrollup

install:
        mov ax,stacksg
        mov ss,ax
        mov sp,128

        mov ax,cs
        mov es,ax
        mov di,offset int9

        mov ax,0
        mov ds,ax
        mov si,200h
        ; 保存原有7ch中断例程入口地址
        mov word ptr ds:[200h],ds:[7ch*4]
        mov word ptr ds:[202h],ds:[7ch*4+2]

        mov cx,offset int7chend - offset int7ch
        cld
        rep movsb
        ; 设置新7ch中断例程入口地址
        cli
        mov word ptr ds:[7ch*4],204h
        mov word ptr ds:[7ch*4+2],0h
        sti

        mov ax,4c00h
        int 21h
uninstall:
        mov ax,0
        mov ds,ax
        ; 判断是否已清空内容，已清空时不需要再次清空
        cmp ds:[204h],0
        je unend
        ; 恢复原有7ch中断例程
        cli    
        mov word ptr ds:[7ch*4],ds:[200h]
        mov word ptr ds:[7ch*4+2],ds:[202h]
        sti
        ; 清空200h之后的内容
        mov cx,offset int7chend - offset int7ch
        mov bx,0
s:      mov byte ptr ds:[200h+bx],0
        inc bx
        loop s
unend:  mov ax,4c00h
        int 21h

int7ch:
        push ax
        cmp ah,0
        je do0
        cmp ah,1
        je do1
        cmp ah,2
        je do2
        cmp ah,3
        je do3
int7chOK:     
        pop ax
        iret
do0:
        call cls
        jmp short int7chOK
do1:
        call setfg
        jmp short int7chOK
do2:
        call setbg
        jmp short int7chOK
do3:
        call scrollup
        jmp short int7chOK
; 清屏
cls:
    push bx
    push cx
    push es
    mov bx,0b800h
    mov es,bx
    mov cx,2000
    mov bx,0
s0:
    mov es:[bx],0
    add bx,2
    loop s0
    pop es
    pop cx
    pop bx
    ret
; 设置前景色
setfg:
    push bx
    push cx
    push di
    push es
    mov bx,0b800h
    mov es,bx
    mov di,1
    mov bl,al
    mov cx,2000
s1:
    and byte ptr es:[di],11111000B
    or byte ptr es:[di],bl
    add di,2
    loop s1
    pop es
    pop di
    pop cx
    pop bx
    ret
; 设置背景色
setbg:
    push bx
    push cx
    push di
    push es
    mov bx,0b800h
    mov es,bx
    mov di,1
    mov bl,al
    ; 将bl转换为0[al]0000B 
    mov cl,4
    shl bl,cl
    mov cx,2000
s1:
    and byte ptr es:[di],10001111B 
    or byte ptr es:[di],bl
    add di,2
    loop s1
    pop es
    pop di
    pop cx
    pop bx
    ret
; 向上滚动一行
scrollup:
    push bx
    push cx
    push di
    push es
    mov bx,0b800h
    mov es,bx
    mov di,0
    mov cx,2000
s1:
        cmp di,160
        jb set0
        mov byte ptr es:[di],es:[di-160]
        jmp short lp
set0:   mov byte ptr es:[di],0
lp:     add di,2
        loop s1
    pop es
    pop di
    pop cx
    pop bx
    ret
int7chend:
    nop

codesg ends
; 测试
codesg2 segment

testcls:
        mov ah,0
        jmp short tend
        
testsetfg:
        mov ah,1
        mov al,2
        jmp short tend

testsetbg:
        mov ah,2
        mov al,5
        jmp short tend
        
testscrollup:
        mov ah,3
        jmp short tend
        
tend:
        int 7ch
        mov ax,4c00h
        int 21h
codesg2 ends

end install